//
//  STDRenderManager.cpp
//  STDRenderSDK
//
//  Created by 陈学明 on 2023/3/13.
//  Copyright © 2023 陈学明. All rights reserved.
//

#include "STDRenderManager.hpp"

void STDRenderManager::addLayer(int layerID, int layerType) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto type = STDLayerType(layerType);
    shared_ptr<STDBaseLayer> layer = nullptr;
    if (type == STDLayerTypeImage) {
        layer = make_shared<STDImageLayer>();
    } else if (type == STDLayerTypeText) {
        layer = make_shared<STDTextLayer>();
    } else if (type == STDLayerTypeVideo) {
        layer = make_shared<STDVideoLayer>();
    } else if (type == STDLayerTypeCompose) {
        layer = make_shared<STDComboLayer>();
    } else if (type == STDLayerTypeShapen) {
        layer = make_shared<STDShapenLayer>();
    } else if (type == STDLayerTypeEmpty) {
        layer = make_shared<STDEmptyLayer>();
    } else if (type == STDLayerTypeCamora) {
        layer = make_shared<STDSCamoraLayer>();
    } else if (type == STDLayerTypeSolidColor) {
        layer = make_shared<STDSSolidColorLayer>();
    }
    if (layer != nullptr) {
        layer->setId(layerID);
        layer->setContext(mContext);
        glm::vec2 point = mContext->getSizeCVS();
        layer->setCenter(vec2(point.x/2.0, point.y/2.0));
    }
    mLayers.push_back(layer);
}

void STDRenderManager::moveLayerToCompose(int layerID, int composeID) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> compose = getLayer(composeID);
    if (compose == nullptr || compose->getType() != STDLayerTypeCompose) {
        return;
    }
    auto composeLayer = dynamic_pointer_cast<STDComboLayer>(compose);
    auto layer = popLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    composeLayer->addLayer(layer);
}

void STDRenderManager::removeLayer(int layerID) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = popLayer(layerID);
    if (layer != nullptr) {
        mContext->autoRelease(layer);
    }
}

void STDRenderManager::setSolidLayerColor(int layerId, float r, float g, float b) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    auto solidLayer = dynamic_pointer_cast<STDSSolidColorLayer>(layer);
    solidLayer->setColor(r, g, b);
}

void STDRenderManager::moveLayerToFront(int layerID, int targetLayerID) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = popLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
    while (it != mLayers.end()) {
        if ((*it)->getId() == targetLayerID) {
            mLayers.insert(++it, layer);
            break;
        }
    }
}

void STDRenderManager::moveLayerToBack(int layerID, int targetLayerID) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = popLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    
    vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
    while (it != mLayers.end()) {
        if ((*it)->getId() == targetLayerID) {
            mLayers.insert(it, layer);
            break;
        }
    }
}

void STDRenderManager::moveLayerToTop(int layerID) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = popLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    mLayers.insert(mLayers.end(), layer);
}

void STDRenderManager::moveLayerToBottom(int layerID) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = popLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    mLayers.insert(mLayers.begin(), layer);
}


void STDRenderManager::moveLayerToFront(int composeID, int layerID, int targetLayerID) {
    if (composeID <= 0) {
        moveLayerToFront(layerID, targetLayerID);
        return;
    }
    shared_ptr<STDBaseLayer> compose = getLayer(composeID);
    if (compose == nullptr || compose->getType() != STDLayerTypeCompose) {
        return;
    }
    auto composeLayer = dynamic_pointer_cast<STDComboLayer>(compose);
    composeLayer->moveLayerToFront(layerID, targetLayerID);
}

void STDRenderManager::moveLayerToBack(int composeID, int layerID, int targetLayerID) {
    if (composeID <= 0) {
        moveLayerToBack(layerID, targetLayerID);
        return;
    }
    shared_ptr<STDBaseLayer> compose = getLayer(composeID);
    if (compose == nullptr || compose->getType() != STDLayerTypeCompose) {
        return;
    }
    auto composeLayer = dynamic_pointer_cast<STDComboLayer>(compose);
    composeLayer->moveLayerToBack(layerID, targetLayerID);
}

void STDRenderManager::moveLayerToTop(int composeID, int layerID) {
    if (composeID <= 0) {
        moveLayerToTop(layerID);
        return;
    }
    shared_ptr<STDBaseLayer> compose = getLayer(composeID);
    if (compose == nullptr || compose->getType() != STDLayerTypeCompose) {
        return;
    }
    auto composeLayer = dynamic_pointer_cast<STDComboLayer>(compose);
    composeLayer->moveLayerToTop(layerID);
}

void STDRenderManager::moveLayerToBottom(int composeID, int layerID) {
    if (composeID <= 0) {
        moveLayerToBottom(layerID);
        return;
    }
    shared_ptr<STDBaseLayer> compose = getLayer(composeID);
    if (compose == nullptr || compose->getType() != STDLayerTypeCompose) {
        return;
    }
    auto composeLayer = dynamic_pointer_cast<STDComboLayer>(compose);
    composeLayer->moveLayerToBottom(layerID);
}

void STDRenderManager::visibleLayer(int layerID, int isVisible) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setVisible(isVisible != 0);
}

void STDRenderManager::setLayerLife(int layerID, float start, float duration) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setLife(vec2(start, duration));
}

void STDRenderManager::setLayerAlpha(int layerID, float alpha) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setAlpha(alpha);
}

void STDRenderManager::setLayerBlend(int layerID, int blend) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setBlend(STDSBlendType(blend));
}

void STDRenderManager::setLayerSize(int layerID, float w, float h) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    auto size = mContext->getSizeSRC();
    layer->setSizeSRC(glm::vec2(w*size.x, h*size.y));
}

void STDRenderManager::setLayerCenter(int layerID, float x, float y) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    auto size = mContext->getSizeSRC();
    layer->setCenter(glm::vec2(x*size.x, y*size.y));
}

void STDRenderManager::setLayerScale(int layerID, float x, float y) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setScale(glm::vec2(x, y));
}

void STDRenderManager::setLayerRotate(int layerID, float angle) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setRotate(angle);
}

void STDRenderManager::setLayerAutoSize(int layerID, bool autoW, bool autoH) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->setAutoSize(autoW, autoH);
}

void STDRenderManager::transformationTranslation(int layerID, float dx, float dy) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->transformationTranslation(dx, dy);
}

void STDRenderManager::transformationScale(int layerID, float dx, float dy) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->transformationScale(dx, dy);
}

void STDRenderManager::transformationRotation(int layerID, float dAngle) {
    std::lock_guard<std::mutex> lock(mMutex);
    shared_ptr<STDBaseLayer> layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->transformationRotation(dAngle);
}

void STDRenderManager::replaceImageAsset(int layerId, int assetId, const char *path) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceImageAsset(assetId, path);
}

void STDRenderManager::replaceImageTex(int layerId, int assetId, const unsigned int textureId, float width, float height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceImageTex(assetId, textureId, width, height);
}

void STDRenderManager::replaceImageData(int layerId, int assetId, const unsigned char *data, float width, float height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceImageData(assetId, data, width, height);
}

void STDRenderManager::replaceMaskAsset(int layerId, int assetId, const char *path) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceMaskAsset(assetId, path);
}

void STDRenderManager::replaceMaskTex(int layerId, int assetId, const unsigned int textureId, float width, float height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceMaskTex(assetId, textureId, width, height);
}

void STDRenderManager::replaceMaskData(int layerId, int assetId, const unsigned char *data, float width, float height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerId);
    if (layer == nullptr) {
        return;
    }
    layer->replaceMaskData(assetId, data, width, height);
}

void STDRenderManager::addEffect(int layerID, int effect) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->addEffect(effect);
}

void STDRenderManager::changeEffectFloatValue(int layerID, int effect, const char *paramName, float *floatValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeEffectFloatValue(effect, paramName, floatValue, n);
}

void STDRenderManager::changeEffectIntValue(int layerID, int effect, const char *paramName, int *intValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeEffectIntValue(effect, paramName, intValue, n);
}

void STDRenderManager::changeEffectStringValue(int layerID, int effect, const char *paramName, const char *stringValue) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeEffectStringValue(effect, paramName, stringValue);
}

void STDRenderManager::changeEffectBitmap(int layerID, int effectType, const char *paramName, const char *data, int width, int height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeEffectBitmap(effectType, paramName, data, width, height);
}

void STDRenderManager::changeEffectTex(int layerID, int effectType, const char *paramName, unsigned int texId, int width, int height) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeEffectTex(effectType, paramName, texId, width, height);
}

void STDRenderManager::removeEffect(int layerID, int effect) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->removeEffect(effect);
}

void STDRenderManager::visibleEffect(int layerID, int effectType, int isVisible) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->visibleEffect(effectType, isVisible != 0);
}

bool STDRenderManager::checkEffectStatus(int layerID, int effectType, const char *label) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return false;
    }
    return layer->checkEffectStatus(effectType, label);
}

void STDRenderManager::addHotEffect(int layerID, const char *effectName, const char *effectRoot) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->addHotEffect(effectName, effectRoot);
}

void STDRenderManager::removeHotEffect(int layerID, const char *effectName) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->removeHotEffect(effectName);
}

void STDRenderManager::changeHotEffectFloatValue(int layerID, const char *effectName, const char *paramName, float *floatValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotEffectFloatValue(effectName, paramName, floatValue, n);
}

void STDRenderManager::changeHotEffectIntValue(int layerID, const char *effectName, const char *paramName, int *intValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotEffectIntValue(effectName, paramName, intValue, n);
}

void STDRenderManager::changeHotEffectStringValue(int layerID, const char *effectName, const char *paramName, const char *stringValue) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotEffectStringValue(effectName, paramName, stringValue);
}


void STDRenderManager::STDRenderManager::visibleHotEffect(int layerID, const char *effectName, int isVisible) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->visibleHotEffect(effectName, isVisible);
}

void STDRenderManager::addHotFilter(int layerID, const char *filter, const char *effectRoot) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->addHotFilter(filter, effectRoot);
}

void STDRenderManager::removeHotFilter(int layerID, const char *filter) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->removeHotFilter(filter);
}

void STDRenderManager::changeHotFilterFloatValue(int layerID, const char *filter, const char *effectName, const char *paramName, float *floatValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotFilterFloatValue(filter, effectName, paramName, floatValue, n);
}

void STDRenderManager::changeHotFilterIntValue(int layerID, const char *filter, const char *effectName, const char *paramName, int *intValue, int n) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotFilterIntValue(filter, effectName, paramName, intValue, n);
}

void STDRenderManager::changeHotFilterStringValue(int layerID, const char *filter, const char *effectName, const char *paramName, const char *stringValue) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->changeHotFilterStringValue(filter, effectName, paramName, stringValue);
}

void STDRenderManager::visibleHotFilter(int layerID, const char *filter, int isVisible) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto layer = getLayer(layerID);
    if (layer == nullptr) {
        return;
    }
    layer->visibleHotFilter(filter, isVisible);
}


shared_ptr<STDBaseLayer> STDRenderManager::getLayer(int layerID) {
    for (auto layer: mLayers) {
        if (layerID == layer->getId()) {
            return layer;
        }
        if (layer->getType() == STDLayerTypeCompose) {
            auto compose = dynamic_pointer_cast<STDComboLayer>(layer);
            auto templayer = compose->getLayer(layerID);
            if (templayer != nullptr) {
                return templayer;
            }
        }
    }
    return nullptr;
}

shared_ptr<STDBaseLayer> STDRenderManager::popLayer(int layerID) {
    shared_ptr<STDBaseLayer> layer = nullptr;
    vector<shared_ptr<STDBaseLayer>>::iterator it = mLayers.begin();
    while (it != mLayers.end()) {
        if ((*it)->getId() == layerID) {
            layer = *it;
            mLayers.erase(it);
            break;
        }
        if ((*it)->getType() == STDLayerTypeCompose) {
            auto compose = dynamic_pointer_cast<STDComboLayer>(*it);
            layer = compose->popLayer(layerID);
            if (layer != nullptr) {
                break;
            }
        }
        it++;
    }
    return layer;
}
